package controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Observable;

import model.CodeLine;
import model.Memory;
import model.Register;

/**
 * Possible changes
 * <ul>
 * <li>Memory content has changed (setRegister() )</li>
 * <li>Pointer value has changed (setPointer)</li>
 * </ul>
 * 
 * @see #setRegister(Collection)
 * @see #setPointer(int)
 */
public class MemoryController extends Observable {

	private Memory memory;

	private static MemoryController instance;

	private MemoryController() {
		memory = Memory.getMemory();
	}

	public static MemoryController getInstance() {
		if (instance == null) {
			instance = new MemoryController();
		}
		return instance;
	}

	public int getPointerPosition() {
		return memory.getPointer();
	}

	public Register getRegisterValue(int index) {
		int i = 0;
		for (Register register : memory.getRegister()) {
			if (i++ == index) {
				return register;
			}
		}
		return null;
	}

	public int getRegisterSize() {
		return memory.getRegister().size();
	}

	public void setRegisterValue(int index, int value) {
		ArrayList<Register> registers = new ArrayList<Register>();
		for (Register register : memory.getRegister()) {
			registers.add(register);
		}
		Register register = buildRegister();
		register.setValue(value);
		registers.add(index, register);
		setRegister(registers);
	}

	public void setRegister(Collection<Register> register) {
		memory.setRegister(register);
		setChanged();
		notifyObservers(RuntimeState.buildCurrentRuntimeState());
	}

	public Collection<Register> getCopyOfRegister() {
		ArrayList<Register> copy = new ArrayList<Register>();
		for (Register original : memory.getRegister()) {
			Register kopie = buildRegister();
			kopie.setValue(original.getValue());
			copy.add(kopie);
		}
		return copy;
	}

	public int getWidth() {
		return memory.getWidth();
	}

	public int getOpcodeWidth() {
		return memory.getOpcodeWidth();
	}

	public int getPointer() {
		return memory.getPointer();
	}

	public void setPointer(int i) {
		memory.setPointer(i);
		hasChanged();
		notifyObservers(RuntimeState.buildCurrentRuntimeState());
	}

	public CodeLine getCodeLine() {
		if (getRegisterValue(getPointer()) != null) {
			return getRegisterValue(getPointer()).getCommand();
		} else {
			return null;
		}
	}

	public static Register buildRegister() {
		return new Register(Memory.getMinCommandSet(), MemoryController
				.getInstance().getWidth(), MemoryController.getInstance()
				.getOpcodeWidth());
	}
}
